package com.fhsk.file.common.utils.jedis;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Random;

/**
 * @Author: Cy
 * @Date: 2019/7/24 11:54
 */
@Data
@Slf4j
@Component
public class RedisLock {

    @Resource
    JedisUtil jedisUtil;

    //锁失效时间（redis锁失效时间,锁的最大存在时间，也就是程序崩溃，没有手动解锁，设置最大失效时间）
    private long lockTimeOut = 20 * 1000;

    //获取锁的等待时间(获取锁重试时间)
//    private long waitTime = 20 * 1000;

    public RedisLock() {

    }

    public RedisLock(long lockTimeOut, long waitTime) {
        this.lockTimeOut = lockTimeOut;
//        this.waitTime = waitTime;
    }

    /**
     * 根据锁名key获取锁的值value（即失效时间），不存在key则返回0
     *
     * @param key
     * @return
     */
    public Long getLockExpireTime(String key) {
        String value = jedisUtil.get(key);
        Long expireTime = 0L;
        if (StringUtils.isNotBlank(value)) {
            expireTime = Long.parseLong(value);
        }
        return expireTime;
    }

    /**
     * 得到锁返回设置的失效时间，得不到锁等待，当超过获取锁的等待时间则不再等待返回0
     *
     * @param key
     * @return
     */
    public long lock(String key) {
//        long retryTime = System.currentTimeMillis() + this.waitTime;
        Random random = new Random();
        for (; ; ) {
            //获取锁，如果不存在锁则设置锁
            if (getLockExpireTime(key).equals(0L)) {
                Long newLockExpireTime = this.lockTimeOut + System.currentTimeMillis() + random.nextInt(500);
                boolean b = jedisUtil.setNX(key, newLockExpireTime.toString());
                if (b){
                    return newLockExpireTime;
                }
            }
            //获取锁，如果锁超时则删除锁并加锁
            if (System.currentTimeMillis() > getLockExpireTime(key)) {
                jedisUtil.del(key);
                Long newLockExpireTime = this.lockTimeOut + System.currentTimeMillis() + random.nextInt(500);
                boolean b = jedisUtil.setNX(key, newLockExpireTime.toString());
                if (b){
                    return newLockExpireTime;
                }
            }
        }
//        throw new UnifiedException("服务器正忙，请重试！");
    }

    /**
     * 得到锁返回设置的失效时间，得不到锁等待，当超过获取锁的等待时间则不再等待返回0
     *
     * @param key
     * @return
     */
    public long lockNotWait(String key) {
        Random random = new Random();
        //获取锁，如果不存在锁则设置锁
        Long lockExpireTime = getLockExpireTime(key);
        //锁存在
        if (!lockExpireTime.equals(0L)) {
            if(System.currentTimeMillis() <= lockExpireTime){
                return 0L;
            }
            //超时，清除锁
            jedisUtil.del(key);
        }
        //锁不存在，或者锁超时，加锁
        Long newLockExpireTime = this.lockTimeOut + System.currentTimeMillis() + random.nextInt(500);
        boolean b = jedisUtil.setNX(key, newLockExpireTime.toString());
        if (b){
            return newLockExpireTime;
        }
        //并发加锁失败
        return 0L;
    }



    /**
     * 先判断自己运行时间是否超过了锁设置时间，是则不用解锁
     *
     * @param key
     */
    public Long unlock(String key, Long expireTime) {
        if (System.currentTimeMillis() < getLockExpireTime(key)) {
            if (getLockExpireTime(key).equals(expireTime)){
              return  jedisUtil.del(key);
            }
        }
        return 0L;
    }

}
